﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;

namespace SHomeWorkshop.LunarTools
{
    public class ArrowPoints
    {
        private Point arrowTopPoint;

        /// <summary>
        /// 箭头起点。
        /// </summary>
        public Point ArrowTopPoint
        {
            get { return arrowTopPoint; }
        }

        /// <summary>
        /// 即“箭头起点”。
        /// </summary>
        public Point ArrowStartPoint
        {
            get { return arrowTopPoint; }
        }

        private Point arrowRealTopPoint;

        /// <summary>
        /// 考虑到线较粗时，箭头尖端如果显示一个方形的线端会很丑。因此，因将线缩短一些。
        /// </summary>
        public Point ArrowRealTopPoint
        {
            get { return arrowRealTopPoint; }
        }

        private Point arrowLeftPoint;

        /// <summary>
        /// 箭头左侧坐标点。
        /// </summary>
        public Point ArrowLeftPoint
        {
            get { return arrowLeftPoint; }
            set { arrowLeftPoint = value; }
        }

        private Point arrowRightPoint;

        /// <summary>
        /// 箭头右侧坐标点。
        /// </summary>
        public Point ArrowRightPoint
        {
            get { return arrowRightPoint; }
            set { arrowRightPoint = value; }
        }

        private Point arrowControlPoint;

        /// <summary>
        /// 箭头控制点坐标（即箭尾坐标）。
        /// 此点和箭头起点的连线将决定箭头的方向。箭头将指向起点（arrowTop）。
        /// </summary>
        public Point ArrowControlPoint
        {
            get { return arrowControlPoint; }
        }

        /// <summary>
        /// 箭头尾坐标。即“箭头控制点”坐标。
        /// </summary>
        public Point ArrowTailPoint
        {
            get { return arrowControlPoint; }
        }


        private double arrowHeight = 10;

        /// <summary>
        /// （箭头左点与右点组成的）底部连线与箭头的顶点（起点）间的垂直距离。
        /// 默认值为10。
        /// </summary>
        public double ArrowHeight
        {
            get { return arrowHeight; }
        }

        /// <summary>
        /// 实例化时，会计算相关值。
        /// </summary>
        /// <param name="arrowTopPoint"></param>
        /// <param name="arrowControl"></param>
        /// <param name="arrowHeight">最小箭头高为10.</param>
        public ArrowPoints(Point arrowTopPoint, Point arrowControl, double arrowHeight = 10)
        {
            this.arrowTopPoint = arrowTopPoint;
            this.arrowControlPoint = arrowControl;
            if (arrowHeight < 10) { this.arrowHeight = arrowHeight = 10; }
            else this.arrowHeight = arrowHeight;

            //算出箭头的左点和右点。

            //如果控制点与顶点是同一点。
            if (arrowTopPoint.X == arrowControl.X && arrowTopPoint.Y == arrowControl.Y)
            {
                arrowRealTopPoint.X = arrowLeftPoint.X = arrowRightPoint.X = arrowTopPoint.X;
                arrowRealTopPoint.Y = arrowLeftPoint.Y = arrowRightPoint.Y = arrowTopPoint.Y;
                return;
            }

            //如果两点横坐标相同。
            if (arrowTopPoint.X == arrowControl.X)
            {
                double r = arrowHeight / Math.Sqrt(3);//r为箭头底线中点与左点（或右点）的距离。
                if (arrowControl.Y > arrowTopPoint.Y)//指向正上方。
                {
                    arrowLeftPoint = new Point(arrowTopPoint.X - r, arrowTopPoint.Y + arrowHeight);
                    arrowRightPoint = new Point(arrowTopPoint.X + r, arrowTopPoint.Y + arrowHeight);
                    arrowRealTopPoint.X = arrowTopPoint.X;
                    arrowRealTopPoint.Y = arrowTopPoint.Y + arrowHeight / 2;
                }
                else//两点重叠的可能性已经排除。
                {
                    arrowLeftPoint = new Point(arrowTopPoint.X + r, arrowTopPoint.Y - arrowHeight);
                    arrowRightPoint = new Point(arrowTopPoint.X - r, arrowTopPoint.Y - arrowHeight);
                    arrowRealTopPoint.X = arrowTopPoint.X;
                    arrowRealTopPoint.Y = arrowTopPoint.Y - arrowHeight / 2;
                }
                return;
            }

            //如果两点横坐标不同。但纵坐标相等。
            if (arrowTopPoint.Y == arrowControl.Y)
            {
                double r = arrowHeight / Math.Sqrt(3);//r为箭头底线中点与左点（或右点）的距离。
                if (arrowControl.X > arrowTopPoint.X)//指正向左方
                {
                    arrowLeftPoint = new Point(arrowTopPoint.X + arrowHeight, arrowTopPoint.Y + r);
                    arrowRightPoint = new Point(arrowTopPoint.X + arrowHeight, arrowTopPoint.Y - r);
                    arrowRealTopPoint.Y = arrowTopPoint.Y;
                    arrowRealTopPoint.X = arrowTopPoint.X + arrowHeight / 2;
                }
                else//指向正右方
                {
                    arrowLeftPoint = new Point(arrowTopPoint.X - arrowHeight, arrowTopPoint.Y + r);
                    arrowRightPoint = new Point(arrowTopPoint.X - arrowHeight, arrowTopPoint.Y - r);
                    arrowRealTopPoint.Y = arrowTopPoint.Y;
                    arrowRealTopPoint.X = arrowTopPoint.X - arrowHeight / 2;
                }
                return;
            }

            //如果两点纵、横坐标皆不等。

            if (arrowControl.X > arrowTopPoint.X)
            {
                //指向左上
                if (arrowControl.Y > arrowTopPoint.Y)
                {
                    double vSideHeight = arrowControlPoint.Y - arrowTopPoint.Y;
                    double hSideWidth = arrowControlPoint.X - arrowTopPoint.X;
                    double sin = vSideHeight / Math.Sqrt(vSideHeight * vSideHeight + hSideWidth * hSideWidth);
                    //sin^2+cos^2=1
                    double cos = Math.Sqrt(1 - sin * sin);

                    Point ptArrowBaseCenter = new Point(
                        arrowTopPoint.X + arrowHeight * cos, arrowTopPoint.Y + arrowHeight * sin);

                    arrowRealTopPoint = new Point(
                        arrowTopPoint.X + (ptArrowBaseCenter.X - arrowTopPoint.X) / 2,
                        arrowTopPoint.Y + (ptArrowBaseCenter.Y - arrowTopPoint.Y) / 2);

                    double tmpLong = arrowHeight / Math.Sqrt(3);//短斜边
                    double tmpWidth = tmpLong * sin;
                    double tmpHeight = tmpLong * cos;
                    arrowLeftPoint = new Point(ptArrowBaseCenter.X - tmpWidth, ptArrowBaseCenter.Y + tmpHeight);
                    arrowRightPoint = new Point(ptArrowBaseCenter.X + tmpWidth, ptArrowBaseCenter.Y - tmpHeight);
                    return;
                }
                else//指向左下
                {
                    double vSideHeight = arrowTopPoint.Y - arrowControlPoint.Y;
                    double hSideWidth = arrowControlPoint.X - arrowTopPoint.X;
                    double sin = vSideHeight / Math.Sqrt(vSideHeight * vSideHeight + hSideWidth * hSideWidth);
                    //sin^2+cos^2=1
                    double cos = Math.Sqrt(1 - sin * sin);

                    Point ptArrowBaseCenter = new Point(
                        arrowTopPoint.X + arrowHeight * cos, arrowTopPoint.Y - arrowHeight * sin);

                    arrowRealTopPoint = new Point(
                        arrowTopPoint.X + (ptArrowBaseCenter.X - arrowTopPoint.X) / 2,
                        arrowTopPoint.Y - (arrowTopPoint.Y - ptArrowBaseCenter.Y) / 2);

                    double tmpLong = arrowHeight / Math.Sqrt(3);//短斜边
                    double tmpWidth = tmpLong * sin;
                    double tmpHeight = tmpLong * cos;
                    arrowLeftPoint = new Point(ptArrowBaseCenter.X + tmpWidth, ptArrowBaseCenter.Y + tmpHeight);
                    arrowRightPoint = new Point(ptArrowBaseCenter.X - tmpWidth, ptArrowBaseCenter.Y - tmpHeight);
                    return;
                }
            }
            else
            {
                //指向右上
                if (arrowControl.Y > arrowTopPoint.Y)
                {
                    double vSideHeight = arrowControlPoint.Y - arrowTopPoint.Y;
                    double hSideWidth = arrowTopPoint.X - arrowControlPoint.X;
                    double sin = vSideHeight / Math.Sqrt(vSideHeight * vSideHeight + hSideWidth * hSideWidth);
                    //sin^2+cos^2=1
                    double cos = Math.Sqrt(1 - sin * sin);

                    Point ptArrowBaseCenter = new Point(
                        arrowTopPoint.X - arrowHeight * cos, arrowTopPoint.Y + arrowHeight * sin);

                    arrowRealTopPoint = new Point(
                        arrowTopPoint.X - (arrowTopPoint.X - ptArrowBaseCenter.X) / 2,
                        arrowTopPoint.Y + (ptArrowBaseCenter.Y - arrowTopPoint.Y) / 2);

                    double tmpLong = arrowHeight / Math.Sqrt(3);//短斜边
                    double tmpWidth = tmpLong * sin;
                    double tmpHeight = tmpLong * cos;
                    arrowLeftPoint = new Point(ptArrowBaseCenter.X - tmpWidth, ptArrowBaseCenter.Y - tmpHeight);
                    arrowRightPoint = new Point(ptArrowBaseCenter.X + tmpWidth, ptArrowBaseCenter.Y + tmpHeight);
                    return;
                }
                else//指向右下
                {
                    double vSideHeight = arrowTopPoint.Y - arrowControlPoint.Y;
                    double hSideWidth = arrowTopPoint.X - arrowControlPoint.X;
                    double sin = vSideHeight / Math.Sqrt(vSideHeight * vSideHeight + hSideWidth * hSideWidth);
                    //sin^2+cos^2=1
                    double cos = Math.Sqrt(1 - sin * sin);

                    Point ptArrowBaseCenter = new Point(
                        arrowTopPoint.X - arrowHeight * cos, arrowTopPoint.Y - arrowHeight * sin);

                    arrowRealTopPoint = new Point(
                        arrowTopPoint.X - (arrowTopPoint.X - ptArrowBaseCenter.X) / 2,
                        arrowTopPoint.Y - (arrowTopPoint.Y - ptArrowBaseCenter.Y) / 2);

                    double tmpLong = arrowHeight / Math.Sqrt(3);//短斜边
                    double tmpWidth = tmpLong * sin;
                    double tmpHeight = tmpLong * cos;
                    arrowLeftPoint = new Point(ptArrowBaseCenter.X + tmpWidth, ptArrowBaseCenter.Y - tmpHeight);
                    arrowRightPoint = new Point(ptArrowBaseCenter.X - tmpWidth, ptArrowBaseCenter.Y + tmpHeight);
                    return;
                }
            }
        }

        public static ArrowPoints GetArrowPoints(Point arrowTopPoint, Point arrowControl, double arrowHeight = 10)
        {
            return new ArrowPoints(arrowTopPoint, arrowControl, arrowHeight);
        }
    }
}
